<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" href="./favicon.ico">
    <title>test_html</title>
    <style>
        * {
            box-sizing: border-box;
        }
        
        html,
        body {
            height: 100%;
            width: 100%;
            box-sizing: border-box;
        }
        
        .all {
            height: 100%;
            width: 100%;
            overflow: auto;
        }
        
        #test {
            /**
            width: 100%;
            height: 100%;
            */
        }
        
        .topic-image {
            visibility: hidden;
            cursor: pointer;
        }
        
        .x6-node:hover .topic-image {
            visibility: visible;
        }
        
        .x6-node-selected rect {
            stroke-width: 2px;
        }
    </style>
    <script src="jquery-3.6.min.js"></script>
    <!-- <script type="module" src="https://unpkg.com/@antv/x6/dist/x6.js"></script> -->
    <script type="module" src="x6.min.js"></script>
    <!-- <script type="module" src="https://unpkg.com/@antv/layout/dist/layout.min.js"></script> -->
    <script type="module" src="x6.layout.min.js"></script>
    <script src="mock.js"></script>
    <link rel="stylesheet" href="./mod/style/main.css">
    <link rel="stylesheet" href="./mod/style/actionMod.css">
    <script type="module" src="./tippy/popperjs.js"></script>
    <script type="module" src="./tippy/tippy.min.js"></script>
    <link rel="stylesheet" href="./tippy/tippy.css">
</head>

<body>

    <div class="all">
        <div id="test">123312</div>
    </div>
    <script type="module">
        import x6MainFn from "./mod/x6Main/index.js"; import { addBtnChildrenTool, addBtnParentTool, decreaseBtnChildrenTool,decreaseBtnParentTool } from "./mod/x6Main/tools.js"; import actionMod from "./mod/html/actionMod.js"; import mainModFn from "./mod/html/mainMod.js";
        window.mainModFn = mainModFn; window.x6MainFn = x6MainFn; window.decreaseBtnParentTool = decreaseBtnParentTool; window.addBtnChildrenTool = addBtnChildrenTool; window.addBtnParentTool = addBtnParentTool; window.decreaseBtnChildrenTool = decreaseBtnChildrenTool;
        window.actionMod = actionMod; import nodeJsonStr from "./nodeJsonStr.js"; window.nodeJsonStr = nodeJsonStr; import edgeJsonStr from "./edgeJsonStr.js"; window.edgeJsonStr = edgeJsonStr;
    </script>
    <script type="text/javascript">
        var graph;
        var nodeData;
        var mainFn = {};
        var rootId;
        var ranksep = 100;
        var nodesep = 25;
        var selectNode = {}; //选中节点
        $(document).ready(function() {
                setTimeout(function() {
                    initEdeg();
                    init()
                }, 300)
            })
            //初始化线条
        function initEdeg() {
            X6.Graph.registerEdge(
                "custom-edge-label", {
                    inherit: "edge",
                    defaultLabel: {
                        markup: [{
                            tagName: "rect",
                            selector: "body",
                        }, {
                            tagName: "text",
                            selector: "label",
                        }, ],
                        attrs: {
                            label: {
                                fill: "#000",
                                fontSize: 14,
                                textAnchor: "middle",
                                textVerticalAnchor: "middle",
                                pointerEvents: "none",
                            },
                            body: {
                                ref: "label",
                                fill: "#ffd591",
                                stroke: "#ffa940",
                                strokeWidth: 2,
                                rx: 4,
                                ry: 4,
                                refWidth: "140%",
                                refHeight: "140%",
                                refX: "-20%",
                                refY: "-20%",
                            },
                        },
                        position: {
                            distance: 0.5,
                            options: {
                                absoluteDistance: true,
                                reverseDistance: true,
                            },
                        },
                    },
                },
                true
            );
        }
        //初始化
        function init() {
            graph = new X6.Graph({
                container: document.getElementById('test'),
                width: 1900,
                height: 1000,
                scroller: {
                    enabled: true, //滚动
                    className: "my-scroller",
                },
                panning: {
                    // enabled: true, //画布可以平移
                    //还可以配置 eventTypes 来设置触发画布拖拽的行为，支持 leftMouseDown、 rightMouseDown、mouseWheel，默认为 ['leftMouseDown'] 。
                    eventTypes: ["leftMouseDown", "rightMouseDown", "mouseWheel"],
                },
                // interacting: { nodeMovable: false },
                // async: true,
                // frozen: true,
                scroller: true,
                // interacting: false,
                background: {
                    color: "#fffbe6", // 设置画布背景颜色
                },
                // selecting: {
                // enabled: true,
                // rubberband: true,
                // showNodeSelectionBox: true,
                // },

                grid: {
                    size: 10, // 网格大小 10px
                    visible: true, // 渲染网格背景
                },
                interacting: {
                    'nodeMovable': false, // 节点是否可以被移动。
                }
            });
            initData();
            mainFn = x6MainFn(graph);
            layoutMain(); //布局函数
            clickAction(); //绑定事件
            let rootNode = mainFn.getById(rootId);
            //增加初始化关系。。。
            initNodeRelationship();
        }
        //数据初始化
        function initData() {
            let data = JSON.parse(localStorage.toJSON);
            nodeData = data;
            rootId = nodeData.nodes[0].data.rootId;
            nodeData.nodes.map((item, i) => {
                let obj = createNode({
                    id: item.id,
                    ...item.data
                });
                nodeData.nodes[i] = obj;
            })
            console.log("nodeData.edges", nodeData.edges);
            nodeData.edges.map((item, i) => {
                item.zIndex = -10
                item.attrs = {
                    line: {
                        stroke: '#A2B1C3',
                        strokeWidth: 2,
                        //targetMarker: null,
                    },
                }
                item.target.port = "port_" + item.target.cell;
                item.connector = {
                    name: 'smooth'
                }
            })
        }
        //初始化节点关系
        function initNodeRelationship() {
            let nodes = mainFn.getNodes();
            //console.log("nodes:", nodes);
            let childrenList = []
            let rootNode = mainFn.getById(rootId);
            mainFn.getEdges().map((item) => {
                let sourceId = item.source.cell;
                let targetId = item.target.cell;
                let sourceNode = mainFn.getById(sourceId);
                let targetNode = mainFn.getById(targetId);
                sourceNode.addChild(targetNode)

            })
            setTimeout(() => {
                let cells = graph.getCells();
                //console.log("---------Cells---------", cells);
                let newModel = {
                    nodes: graph.getNodes(),
                    edges: graph.getEdges(),
                }
                newModel = graph.toJSON(newModel);
                graph.fromJSON(newModel);
                //graph.fromJSON(newModel); toJSON(...) parseJSON(...)
            }, 1000)
        }
        //布局函数
        function layoutMain() {
            graph.freeze();
            let hideNodeList = mainFn.nodeIsShowFn(); //获取要隐藏的节点
            const {
                DagreLayout
            } = window.layout;

            const dagreLayout = new DagreLayout({
                type: "dagre",
                rankdir: "LR",
                align: "",
                ranksep: ranksep,
                nodesep: nodesep,
                controlPoints: true,
            });
            let newModel = {}

            let dataJson = getLayoutData();
            if (dataJson && dataJson.nodes && dataJson.nodes.length > 0) {
                console.log("---------dagreLayout --newModel---------", dataJson);
                newModel = dagreLayout.layout(dataJson);
                console.log("newModel", newModel)
                graph.fromJSON(newModel);
            } else {
                console.log("nodeData", nodeData)
                newModel = dagreLayout.layout(nodeData);
                //console.log("newModel", newModel)
                graph.fromJSON(newModel);
                console.log("graph", mainFn.getNodes());
            }




            //隐藏对应节点
            for (const key in hideNodeList) {
                if (hideNodeList.hasOwnProperty.call(hideNodeList, key)) {
                    const element = hideNodeList[key];
                    element.map((item) => {
                        let node = mainFn.getById(item);
                        node.data.showFlag = false;
                        node.hide();
                    });
                }
            }
            graph.unfreeze();

        }
        //返回布局格式
        function getLayoutData() {

            let nodes = [];
            let edges = [];
            //edgeJsonStr
            //nodeJsonStr
            graph.getNodes().map(item => {
                let nodeObj = {}
                for (let i = 0; i < nodeJsonStr.length; i++) {
                    let str = nodeJsonStr[i];
                    nodeObj[str] = item[str];
                }
                //手动添加宽高
                nodeObj.height = 60
                nodeObj.width = 200

                nodes.push(nodeObj)
            })
            graph.getEdges().map(item => {
                let edgeObj = {}
                for (let i = 0; i < edgeJsonStr.length; i++) {
                    let str = edgeJsonStr[i];
                    edgeObj[str] = item[str];
                }
                edges.push(edgeObj)
            })
            return {
                nodes,
                edges
            };
        }
        //绑定事件
        function clickAction() {
            graph.on("node:mousedown", ({
                e,
                x,
                y,
                node,
                view
            }) => {
                alert("节点信息" + node.data.text[0])
                console.log("node", node)
                console.log("getDescendants", node.getDescendants())

            });
            graph.on("edge:mousedown", ({
                e,
                x,
                y,
                edge,
                view
            }) => {
                alert("边线:click");
                console.log("edge", edge)
            });
            graph.on("blank:click", ({
                e,
                x,
                y
            }) => {

            });

            graph.on("node:mouseenter", ({
                e,
                x,
                y,
                node
            }) => {

                let data = node.getData();

                if (data.root) {
                    //根节点处理
                    getRootTools(node);
                } else if (data.dir == "down" && data.tools) {
                    //下游节点处理
                    getDownTools(node);
                } else if (data.dir == "up" && data.tools) {
                    //上游节点处理
                    getUpTools(node);
                }

            });
            graph.on("node:mouseleave", ({
                e,
                x,
                y,
                node
            }) => {
                //移出
                node.removeTools();
            });
        }
        //创建节点数据结构
        function createNode({
            id = new Date().getTime(),
            root = false,
            dir = "down",
            type = "tab",
            text = "test text",
            time = new Date().toString(),
            tools = true,
            data = {}
        }) {
            let title = type == "tab" ? "表" : "API";
            let Markup = X6.Markup;
            return {
                id: id,
                width: 200,
                height: 60,
                shape: "html",
                data: {
                    time,
                    type,
                    dir,
                    showFlag: true,
                    rootId: rootId,
                    root: root,
                    title: title,
                    text: text,
                    tools,
                    ...data
                },
                //portMarkup: [Markup.getForeignObjectMarkup()],
                ports: [{
                    id: 'port_' + id,
                    position: 'left',
                    attrs: {
                        circle: {
                            magnet: false,
                            stroke: 'transparent',
                            strokeWidth: 1,
                            fill: 'red',
                            stroke: '#red',
                            r: 0,
                            rx: 100,

                        },
                    },
                    zIndex: -1
                }],
                html: {
                    render(node) {
                        const data = node.getData();
                        return actionMod(data);
                    },
                    shouldComponentUpdate(node) {
                        // 控制节点重新渲染
                        return node.hasChanged("data");
                    },
                },
            };
        }
        //类型节点
        function mainNode({
            id = "" + new Date().getTime(),
            type = "end",
            dir = "down",
            rootId = window.rootId,
            root = false,
            showFlag = true,
        }) {
            return {
                id: id,
                width: 62,
                height: 62,
                shape: "html",
                data: {
                    time: "" + new Date().toString(),
                    type: type ? type : "node",
                    title: type == "end" ? "结束" : type,
                    dir,
                    rootId,
                    root,
                    showFlag
                },
                html: {
                    render(node) {
                        if (type == "end") {
                            return `<div title="结束"><img src="./mod/img/end.svg" /></div>`
                        } else if (type == "start") {
                            return `<div title="开始"><img src="./mod/img/start.svg" /></div>`
                        } else {
                            return mainModFn(type);
                        }

                    },
                    shouldComponentUpdate(node) {
                        // 控制节点重新渲染
                        return node.hasChanged("data");
                    },
                },
            }
        }
        //根节点工具
        function getRootTools(node) {
            getDownTools(node);
            getUpTools(node);
        }
        //下游节点工具处理
        function getDownTools(node) {
            //开始隐藏节点
            let childrenFlag = mainFn.getEdges().find((item) => {
                return item.source.cell == node.id;
            });

            if (!childrenFlag && !node.data.leafNode) {
                //没有子节点
                //node.addTools(addBtnChildrenTool(this.add));
                node.addTools(addBtnChildrenTool(add));
            } else {
                //有子节点 使用显示或隐藏
                if (!node.data.leafNode && childrenFlag) { //非叶子节点才有工具
                    let child = mainFn.getById(childrenFlag.target.cell);
                    let item = child[0] ? child[0] : child;
                    if (item.visible) {
                        //添加隐藏工具
                        node.addTools(decreaseBtnChildrenTool(hideCell));
                    } else {
                        //添加显示工具
                        node.addTools(addBtnChildrenTool(showCell));
                    }
                }

            }
        }
        //上游节点工具处理
        function getUpTools(node) {
            let parentFlag = mainFn.getEdges().find((item) => {
                return item.target.cell == node.id;
            });

            if (!parentFlag && !node.data.leafNodeUP) {
                node.addTools(addBtnParentTool(add));
            } else {
                if (!node.data.leafNodeUp && parentFlag) { //非叶子节点才有工具
                    //有子节点 使用显示或隐藏
                    let parent = mainFn.getById(parentFlag.source.cell);
                    let item = parent[0] ? parent[0] : parent;

                    if (item.visible) {
                        //添加隐藏工具
                        node.addTools(decreaseBtnParentTool(hideCell));
                    } else {
                        //添加显示工具
                        node.addTools(addBtnParentTool(showCell));
                    }
                }


            }
        }
        //显示相关节点和边
        function showCell(node, dir) {
            let id = node.id;

            //1. 根据节点id和方向找到上游或者下游节点
            let edges = mainFn.getEdges();
            let list1Node = []; //第一层子节点
            for (let i = 0; i < edges.length; i++) {
                let item = edges[i];
                if (dir == "down") { //处理子节点 if
                    if (item.source.cell == id) {
                        let target = item.target.cell;
                        let targetNode = mainFn.getById(target);
                        targetNode.data.showFlag = true;
                        targetNode.setVisible(true)
                        list1Node.push(targetNode.id);
                    }
                } else if (dir == "up") { //处理父节点 if
                    if (item.target.cell == id) {
                        let source = item.source.cell;
                        let sourceNode = mainFn.getById(source);
                        sourceNode.data.showFlag = true;
                        sourceNode.setVisible(true, {
                            silent: false
                        })
                        list1Node.push(sourceNode.id);
                    }
                }
            }
            console.log("list1Node", list1Node)
            let sonIdList = []
                //2. 根据节点id找到他们后续关联节点的边id
            for (let i = 0; i < list1Node.length; i++) {
                let item = list1Node[i];

            }

            function findSonNode(id) {

            }
            //3. 只有对联节点第一层必须显示，子孙节点原来隐藏的继续隐藏，非隐藏的显示
            findNode(id);

            function findNode(id) {
                let edges = mainFn.getEdges();

                edges.map((item) => {
                    if (dir == "down") {
                        //处理子节点
                        let source = item.source.cell;
                        if (source == id) {
                            let target = item.target.cell;
                            let targetNode = mainFn.getById(target);
                            targetNode.data.showFlag = true;
                            targetNode.setVisible(true)
                            findNode(targetNode.id);
                        }
                    } else if (dir == "up") {
                        //处理父节点
                        let target = item.target.cell;
                        if (target == id) {
                            let source = item.source.cell;
                            let sourceNode = mainFn.getById(source);
                            sourceNode.data.showFlag = true;
                            sourceNode.setVisible(true)
                            findNode(sourceNode.id);
                        }
                    }
                });
            }
            node.removeTools();
            //layoutMain();
        }
        //隐藏相关节点和边
        function hideCell(node, dir) {
            let id = node.id;
            findNode(id);

            function findNode(id) {
                let edges = mainFn.getEdges();

                edges.map((item) => {
                    if (dir == "down") {
                        //处理子节点
                        let source = item.source.cell;
                        if (source == id) {
                            let target = item.target.cell;
                            let targetNode = mainFn.getById(target);
                            targetNode.data.showFlag = false;
                            // targetNode.hide();
                            targetNode.setVisible(false)
                            findNode(targetNode.id);
                        }
                    } else if (dir == "up") {
                        //处理父节点
                        let target = item.target.cell;
                        if (target == id) {
                            let source = item.source.cell;
                            let sourceNode = mainFn.getById(source);
                            sourceNode.data.showFlag = false;
                            // sourceNode.hide();
                            sourceNode.setVisible(false)
                            findNode(sourceNode.id);
                        }
                    }
                });
            }
            node.removeTools();
        }
        //添加节点步骤
        function add(node, dir, data) {

            let flag = Math.round(Math.random());
            //接口数据获取   这里使用随机数1就添加节点，0就结束步骤
            if (flag) {
                let data = {
                    id: Mock.mock("@id"),
                    type: Mock.mock('@pick(["tab", "api"])'),
                    text: [Mock.mock("@name(1)")],
                    data: {
                        myName: "我是自有属性"
                    },
                    dir
                }; //数据内容
                addNode(node, dir, data);
            } else {
                // 没有查询到数据即为叶子节点
                let dataObj = {
                    leafNode: true
                };
                if (dir == "up") {
                    dataObj = {
                        leafNodeUP: true
                    };
                }
                let leafNode = findNodeFn({
                    id: node.id,
                    data: dataObj
                }); //设置为叶子节点
                selectNode = leafNode;
                //addEndNode(node, dir);
                alert("我是叶子节点");

            }
        }
        //添加节点
        function addNode(node, dir, data) {

            let nodeObj = createNode(data)

            let parentNode = {};
            let childrenNode = {};
            let parentId = "";
            if (node && dir == "down") {
                //有指定节点就使用指定节点
                //parentId = node.id;
                parentNode = node;
                //nodeObj.parent = parentId;
            } else if (node && dir == "up") {
                let childId = node.id;
                //nodeObj.children = childId;
            }
            nodeData.nodes.push(nodeObj);

            nodeData.edges.push({
                source: dir == "down" ? node.id : nodeObj.id,
                target: dir == "down" ? nodeObj.id : node.id,
                shape: "custom-edge-label",
                // labels: ["步骤过程"],
                attrs: {
                    line: {
                        stroke: "#A2B1C3",
                        strokeWidth: 2,
                    },
                },
                data: {
                    dir
                }
            });


            if (node && dir == "down") {
                let tempNode = mainFn.getById(nodeObj.id);
                parentNode.addChild(tempNode);
                //tempNode.addTo(parentNode)
            } else if (node && dir == "up") {
                parentNode = mainFn.getById(nodeObj.id);
                let childNode = mainFn.getById(node.id);
                parentNode.addChild(childNode);
                //childNode.addTo(parentNode)
                //childNode.insertTo(parentNode);
            }
            layoutMain();

        }
        //添加结束节点
        function addEndNode(node, dir) {

            let type = dir == "down" ? "end" : "start";
            let nodeObj = mainNode({
                type: type,
                dir
            });
            let parentNode = {};
            let childrenNode = {};
            let parentId = "";
            if (node && dir == "down") {
                //有指定节点就使用指定节点
                parentId = node.id;
                parentNode = node;
                nodeObj.parent = parentId;
            } else if (node && dir == "up") {
                let childId = node.id;
                //nodeObj.children = childId;
            }
            nodeData.nodes.push(nodeObj);

            nodeData.edges.push({
                source: dir == "down" ? node.id : nodeObj.id,
                target: dir == "down" ? nodeObj.id : node.id,
                shape: "custom-edge-label",
                // labels: ["步骤过程"],
                attrs: {
                    line: {
                        stroke: "#A2B1C3",
                        strokeWidth: 2,
                    },
                },
            });
            layoutMain();

            if (node && dir == "down") {
                let tempNode = mainFn.getById(nodeObj.id);
                parentNode.addChild(tempNode);
            } else if (node && dir == "up") {
                parentNode = mainFn.getById(nodeObj.id);
                let childNode = mainFn.getById(node.id);
                parentNode.addChild(childNode);

            }

        }

        function centerFn() {
            let dom = $(".my-scroller");
            if (dom && dom.length > 0) {
                dom = dom[0];
            }
            let width = parseInt(dom.style.width)
            console.log("dom----", dom);
            console.log("width----", width);
            console.log("dom-----scrollTop", dom.scrollTop);
            console.log("dom-----scrollLeft", dom.scrollLeft);
            dom.scrollLeft = width / 2
            console.log("dom-----scrollLeft", dom.scrollLeft);
        }
        /**
         * 根据id查询返回node，没有id就返回全部nodes
         * @param id 节点id
         * @param dataObj 需要变革的节点data信息
         */
        function findNodeFn({
            id = null,
            data = ""
        }) {
            try {
                let node = {}
                if (id) {
                    node = mainFn.getById(id);
                    if (node && node.data && data) {
                        node.data = {
                            ...node.data,
                            ...data
                        };
                        nodeData.nodes.map(item => {
                            if (item.id == node.id) {
                                item.data = node.data;
                            }
                        })
                    }
                } else {
                    node = mainFn.getNodes();
                    if (node && node.length > 0 && data) {
                        node.map(item => {
                            item.data = {
                                ...item.data,
                                ...data
                            };
                            nodeData.nodes.map(it => {
                                if (it.id == item.id) {
                                    it.data = item.data;
                                }
                            })
                        })
                    }
                }
                return node;
            } catch (e) {
                console.log("function ", arguments, " error", e)
            }
        }
    </script>
</body>

</html>